`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    11:01:18 03/30/2014 
// Design Name: 
// Module Name:    ALU 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module ALU(ALU_Out,halt_out,branch_out,vid_line,aud_line,poll_line,cmp_flag,
			  in_1,in_2,opcode,reset,clk);
input [width-1:0] in_1, in_2;
input [4:0] opcode;
input reset,clk;//reset and end_halt pinned to button
output wire branch_out, halt_out, vid_line;
output wire [3:0] aud_line, poll_line;
output [width-1:0] ALU_Out;
////////////////////////////////
//
// general params
//
////////////////////////////////
parameter width = 8;
////////////////////////////////
//
// opcodes to make life easy
//
////////////////////////////////
parameter VID = 5'd0; //refresh video
parameter AUD = 5'd1; //play note
parameter POLL = 5'd2; //poll user
parameter SET = 5'd3; //set reg
parameter MOV = 5'd4; //Move reg
parameter LOAD = 5'd5; //Load from mem
parameter SAVE = 5'd6; //Save to mem
parameter ADD = 5'd7; //Add two regs
parameter SUB = 5'd8; //subtract two regs
parameter MUL = 5'd9; //multiply two regs
parameter XOR = 5'd10; //xor
parameter ADDI = 5'd11; //these are math on immediate values
parameter SUBI = 5'd12;
parameter MULI = 5'd13;
parameter EQ = 5'd14; // equality checks
parameter NEQ = 5'd15;
parameter GT = 5'd16; // greater than
parameter LT = 5'd17;
parameter GE = 5'd18; // greater than equal to
parameter LE = 5'd19;
parameter JUMP = 5'd20; //raw jump
parameter JT = 5'd21; //conditioned jumps
parameter JF = 5'd22;
//Halt for debug
parameter HALT =5'd31;
////////////////////////////////
//
// Internal wires and regs
//
////////////////////////////////
//pin to LEDs
output reg [1:0] cmp_flag = 2'b01; // 11 values are equal 00 not equal 01 or 10 inderminate
////////////////////////////////
//
// Hardware description
//
////////////////////////////////
assign vid_line = (opcode == VID) ? 1'b1 : 1'b0;
assign aud_line = (opcode == AUD) ? in_2[3:0] : 4'd0;
assign poll_line = (opcode == POLL) ? 1'b1 : 1'b0;
// determine the flag for cmp
// 1 - indeterminate
// 0 false
// 3 true
always @(posedge clk)
	if(reset)
		cmp_flag = 2'd1;
	else if(opcode == EQ)
		cmp_flag = (in_1 == in_2) ? 2'd3 : 2'd0;
	else if(opcode == NEQ)
		cmp_flag = (in_1 == in_2) ? 2'd0 : 2'd3;
	else if(opcode == GT)
		cmp_flag = (in_1 > in_2) ? 2'd3 : 2'd0;
	else if(opcode == LT)
		cmp_flag = (in_1 < in_2) ? 2'd3 : 2'd0;
	else if(opcode == GE)
		cmp_flag = ((in_1 > in_2)||(in_1 == in_2)) ? 2'd3 : 2'd0;
	else if(opcode == LE)
		cmp_flag = ((in_1 < in_2)||(in_1 == in_2)) ? 2'd3 : 2'd0;
	else if((opcode == JUMP) || (opcode == JT) || (opcode == JF)) //jump codes set the flags to 1
		cmp_flag = 2'd1;
	else
		cmp_flag = cmp_flag;

//halt control
assign halt_out = (opcode == HALT) ? 1'b1: 1'b0;

//branching output
assign branch_out =  (opcode == JUMP) ? 1'b0:
					 ((opcode == JF) && (cmp_flag == 0)) ? 1'b1:
					 ((opcode == JT) && (cmp_flag == 3)) ? 1'b1:
					 1'b0;

//giving the result
assign ALU_Out =  (opcode == VID) ? 8'd0:
				  (opcode == AUD) ? 8'd1:
				  (opcode == POLL) ? 8'd2:
				  (opcode == SET) ? in_2:
				  (opcode == MOV) ? in_2:
				  (opcode == LOAD) ? in_2:
				  (opcode == SAVE) ? in_1:
				  (opcode == ADD) ? in_1+in_2:
				  (opcode == SUB) ? in_1-in_2:
				  (opcode == MUL) ? in_1*in_2:
				  (opcode == XOR) ? in_1^in_2:
				  (opcode == ADDI) ? in_1+in_2:
				  (opcode == SUBI) ? in_1-in_2:
				  (opcode == MULI) ? in_1*in_2:
				  (opcode == EQ) ? 8'd3:
				  (opcode == NEQ) ? 8'd4:
				  (opcode == GT) ? 8'd5:
				  (opcode == LT) ? 8'd6:
				  (opcode == GE) ? 8'd7:
				  (opcode == LE) ? 8'd8:
				  (opcode == JUMP) ? 8'd9:
				  (opcode == JT) ? 8'd10:
				  (opcode == JF) ? 8'd11:
				  (opcode == HALT) ? 8'd12:
				   16'd0;
endmodule
